package com.gogo.mall.utils;


import com.gogo.mall.entity.QyMember;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * jwt工具类 生成、解析、校验token
 */
public class JwtUtil {
    /**
     * 用户登录成功后生成jwt
     * 使用Hs256算法
     * 三部分组成 头部+荷载+签证信息
     * @param ttlMillis jwt过期时间
     * @param user      登录成功的user对象
     * @return
     */
    public static String createJwt(long ttlMillis, QyMember user){
        // header部分，jwt已经封装好了
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // jwt生成时间 当前时间
        long nowMillis = System.currentTimeMillis();
        Date date = new Date(nowMillis);

        // payload 荷载部分（存放有效信息的地方，包含标准中注册的声明、公共声明、私有声明）
        // 创建私有声明
        Map<String,Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("telphone",user.getTelphone());
        claims.put("password",user.getPassword());

        // 生成秘钥secret用
        byte[] bytes = user.getPassword().getBytes();
        // 生成签发人
        String subject = user.getTelphone();

        // 为payload添加标准声明和私有声明（new一个JwtBuilder，设置jwt的body）
        JwtBuilder jwtBuilder = Jwts.builder()
                // 先设置自己创建的私有声明，要是写在标准声明后面，会覆盖掉标准声明
                .setClaims(claims)
                // 设置jti（jwt id），主要用来作为一次性token，从而回避重放攻击
                .setId(UUID.randomUUID().toString())
                // 设置iat jwt签发时间
                .setIssuedAt(date)
                // 设置jwt的所有人
                .setSubject(subject)
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(signatureAlgorithm, bytes);
        // 设置jwt的过期时间
        if(ttlMillis>= 0){
            long expMillis = ttlMillis*1000+nowMillis;
            Date expDate = new Date(expMillis);
            jwtBuilder.setExpiration(expDate);
        }
        return jwtBuilder.compact();
    }

    /**
     * 解密jwt
     * @param token 需要被解密的token
     * @param user 用户的对象
     * @return
     */
    public static Claims parseJWT(String token,QyMember user){
        // 签名秘钥（与生成签名的秘钥一样）
        byte[] key = user.getPassword().getBytes();
        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(key)
                // 设置需要解析的jwt
                .parseClaimsJws(token).getBody();
        return claims;
    }

    /**
     * 判断jwt是否过期
     */
    public static boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }

    /**
     * 校验jwt
     * 判断token携带的密码跟数据库里的是否一致（也可用官方的校验方法）
     * @param token
     * @param user
     * @return
     */
    public static Boolean isVerify(String token,QyMember user){
        // 秘钥
        byte[] bytes = user.getPassword().getBytes();

        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(bytes)
                // 设置需要解析的jwt
                .parseClaimsJws(token)
                .getBody();
//        System.out.println("claims-----》"+claims);
        // 判断密码是否一致
        if(claims.get("password").equals(user.getPassword())){
            return true;
        }
        return false;
    }
}

